import type {
  AbortControllerType,
  CreateHttpGetFactoryRequest,
  CreateHttpGetFactoryResponse,
  CreateHttpPostFactoryRequest,
  CreateHttpPostFactoryResponse,
  HttpRequestQueryType,
  ResponseDataType,
  successTipsType,
} from "@type/utils/http";
import httpRequest from "./request";
import { isRef, ref, watch } from "vue";
import type { Ref } from "vue";
import type { AxiosRequestConfig } from "axios";

/**
 * 将ref声明的参数处理成正常参数，而不是对象
 * @param query
 * @returns
 */
function dealwithQuery<Request>(query?: HttpRequestQueryType<Request>) {
  let params: { [key: string]: any } = {};
  if (query) {
    for (const key in query) {
      if (Object.prototype.hasOwnProperty.call(query, key)) {
        const info = query[key];
        params[key] = isRef(info) ? info.value : info;
      }
    }
  }
  return params;
}

export function createHttpGetFactory<
  Request extends { [key: string]: Ref<any> | any },
  Response
>(url: string, type: "get" | "delete" = "get", options: AxiosRequestConfig<Request> = {}) {
  // 生产一个hook函数
  return function useGetRequest<Transform = Response>({
    enabled,
    query,
    watchKeys,
    onSuccess = (data: any) => data,
    onError = (_error: any) => { },
    onFinally = (stopLoading: () => void) => stopLoading(),
  }: CreateHttpGetFactoryRequest<
    Request,
    Response,
    Transform
  >): CreateHttpGetFactoryResponse<Request, Response, Transform> {
    // 定义三个变量作为结构内容使用
    const loading = ref(false);
    const error = ref(false);
    const data = ref<Transform | null>(null);

    // 取消请求
    let abortController: AbortControllerType = {
      cancel: () => { },
      target: null,
    };

    const getDataToServer = (
      params?: Request
    ): Promise<[Response | Transform, Response] | void> => {
      abortController.target = new AbortController();
      abortController.cancel = () => abortController.target?.abort();
      loading.value = true;
      const queryInfo = dealwithQuery(query);
      const paramsInfo = dealwithQuery(params);
      return httpRequest[type](url, {
        params: { ...paramsInfo, ...queryInfo },
        signal: abortController.target.signal,
        ...options,
      })
        .then((res: any) => {
          let dealwithData = onSuccess(res);
          data.value = dealwithData;
          return [dealwithData, res] as [Response | Transform, Response];
        })
        .catch((_error) => {
          error.value = true;
          onError(_error);
        })
        .finally(() => {
          onFinally(() => (loading.value = false));
        });
    };

    // 传入新参数 重新请求
    const execute = (query?: Request) => getDataToServer(query);

    const enabledIsBol = typeof enabled === "boolean";
    // 监听参数改变时重新发请求
    watch<Request, true>(
      () => {
        let watchInfo: any = {};
        watchKeys?.forEach((key: string) => {
          watchInfo[key] = query[key];
        });
        return watchInfo;
      },
      (newVal, oldVal) => {
        const isRequest = enabledIsBol ? enabled : enabled(newVal, oldVal);
        if (isRequest) {
          getDataToServer(newVal);
        }
      },
      {
        immediate: true,
        deep: true,
      }
    );

    return [
      {
        loading: loading,
        data: data,
        error: error,
      },
      { execute, abortController },
    ];
  };
}

export function createHttpPostFactory<
  Request extends { [key: string]: Ref<any> | any },
  Response
>(url: string, type: "post" | "put" = "post", options: AxiosRequestConfig<Request> = {}) {
  // 生产一个hook函数
  return function usePostRequest<Transform = Response>({
    query,
    successTips = "请求成功",
    onSuccess = (_data: Response) => _data,
    onError = (_error) => { },
    onFinally = (stopLoading) => stopLoading(),
  }: CreateHttpPostFactoryRequest<
    Request,
    Response,
    Transform
  >): CreateHttpPostFactoryResponse<Request, Response, Transform> {
    // 定义三个变量作为结构内容使用
    const loading = ref(false);
    const error = ref(false);

    // 取消请求
    let abortController: AbortControllerType = {
      cancel: () => { },
      target: null,
    };

    const postDataToServer = (
      params?: Request,
      tips?: successTipsType
    ): Promise<[Response | Transform, Response] | void> => {
      abortController.target = new AbortController();
      abortController.cancel = () => abortController.target?.abort();
      loading.value = true;
      const queryInfo = dealwithQuery(query);
      const paramsInfo = dealwithQuery(params);
      return httpRequest[type]<ResponseDataType<Response>>(
        url,
        { ...paramsInfo, ...queryInfo },
        {
          signal: abortController.target.signal,
          ...options,
        }
      )
        .then((res: any) => {
          if (tips || successTips) {
            alert( "请求成功");
          }
          const dealwithData = onSuccess(res);
          return [dealwithData, res] as [Response | Transform, Response];
        })
        .catch((_error) => {
          error.value = true;
          onError(_error);
        })
        .finally(() => {
          onFinally(() => (loading.value = false));
        });
    };

    // 传入新参数 重新请求
    const execute = (query?: Request, tips?: successTipsType) =>
      postDataToServer(query, tips);

    return [
      {
        loading: loading,
        error: error,
      },
      { execute, abortController },
    ];
  };
}
